<template>
  <!-- 航线规划 -->
  <div class="uvaRoutePlanBox" :class="{ hide: !isShow, show: isShow }">
    <div id="cesiumContainerBox" />
    <div id="toolTip" />
    <div class="body">
      <div class="form-item">
        <span class="form-label"> 航飞区域 </span>
        <div class="form-connect">
          <el-button type="primary" style="width: 130px" @click="drawPoly">
            绘制
          </el-button>
        </div>
      </div>
      <div class="form-item">
        <span class="form-label">航飞间距</span>
        <div class="form-connect">
          <el-input-number
            v-model="hfDistance"
            controls-position="right"
            :min="10"
            :step="10"
            @change="distanceHandleChange"
          />
        </div>
      </div>
      <div class="form-item">
        <div class="form-connect">
          <el-button type="primary" @click="beginCalc"> 开始计算 </el-button>
          <el-button type="success" @click="moniFly"> 模拟飞行 </el-button>
          <el-button type="danger" @click="cleanEntity">清除</el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import * as turf from "@turf/turf";
// 组件引入比较麻烦，直接采用cdn引入
var Cesium = window.Cesium;

var polyArr = []; // 面数据
var jdArrs = []; // 交点集合
export default {
  name: "UvaRoutePlan",
  components: {},
  props: [],
  data() {
    return { isShow: true, hfDistance: 100, isFly: false };
  },
  watch: {},
  created() {
    this.$nextTick(function () {
      this.startInit();
    });
  },
  mounted() {},
  methods: {
    startInit() {
      const key =
        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3YmEwMGRiNC0zYmJmLTQ2OTctOGNkYy1jZGVhYTk4OGQzYWEiLCJpZCI6NDU3NzUsImlhdCI6MTY4OTkwMzk4NH0.mqatlMcOeKyUHBMERanfWS7LsMTI8CGe8DadmLNNAVU";
      Cesium.Ion.defaultAccessToken = key;

      var viewer = new Cesium.Viewer("cesiumContainerBox", {
        imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
          url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
        }),
        geocoder: true,
        homeButton: true,
        sceneModePicker: true,
        baseLayerPicker: true,
        navigationHelpButton: true,
        shouldAnimate: true,
        animation: true,
        timeline: true,
        fullscreenButton: true,
        vrButton: true,
        // 关闭点选出现的提示框
        selectionIndicator: false,
        infoBox: false,
      });
      viewer._cesiumWidget._creditContainer.style.display = "none"; // 隐藏版权
      viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(
          113.6440552299206,
          34.78411814959118,
          2000
        ),
        orientation: {
          heading: Cesium.Math.toRadians(0.0), // 左右方向
          pitch: Cesium.Math.toRadians(-90.0), // 上下方向
          roll: Cesium.Math.toRadians(0), // 镜头（屏幕）到定位目标点（实体）的距离
        },
        duration: 3, // 执行定位动画的时间
      });
      window.viewer = viewer;
    },
    endClose() {
      this.cleanEntity();
    },
    // 画航飞区域
    drawPoly() {
      var viewer = window.viewer;
      this.cleanEntity();
      var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      // 鼠标事件
      handler = new Cesium.ScreenSpaceEventHandler(
        viewer.scene._imageryLayerCollection
      );
      polyArr = [];
      var positions = [];
      var tempPoints = [];
      var polygon = null;
      var tooltip = document.getElementById("toolTip");
      var cartesian = null;
      // 鼠标移动事件
      handler.setInputAction(function (movement) {
        tooltip.style.left = movement.endPosition.x + 3 + "px";
        tooltip.style.top = movement.endPosition.y - 25 + "px";
        tooltip.innerHTML = "<p>单击开始，右击结束</p>";
        const ray = viewer.camera.getPickRay(movement.endPosition);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (positions.length >= 2) {
          if (!Cesium.defined(polygon)) {
            polygon = new PolygonPrimitive(positions);
          } else {
            positions.pop();
            positions.push(cartesian);
          }
        }
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
      // 左击鼠标事件
      handler.setInputAction(function (movement) {
        tooltip.style.display = "block";
        tooltip.style.left = movement.position.x + 3 + "px";
        tooltip.style.top = movement.position.y - 25 + "px";
        tooltip.innerHTML = "<p>单击开始，右击结束</p>";
        const ray = viewer.camera.getPickRay(movement.position);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (positions.length === 0) {
          positions.push(cartesian.clone());
        }

        // positions.pop();
        positions.push(cartesian);
        // 在三维场景中添加点
        var cartographic = Cesium.Cartographic.fromCartesian(
          positions[positions.length - 1]
        );
        var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
        var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
        var heightString = cartographic.height;
        tempPoints.push({
          lon: longitudeString,
          lat: latitudeString,
          hei: heightString,
        });
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
      // 右击鼠标事件
      handler.setInputAction(function () {
        handler.destroy();
        tooltip.style.display = "none";
        positions.pop();
        polyArr = positions;
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      var PolygonPrimitive = (function () {
        function _(positions) {
          this.options = {
            name: "uav-poly",
            polygon: {
              hierarchy: [],
              // perPositionHeight : true,
              material:
                Cesium.Color.fromCssColorString("#fafafa").withAlpha(0.5),
            },
          };

          this.hierarchy = { positions };
          this._init();
        }

        _.prototype._init = function () {
          var _self = this;
          var _update = function () {
            return _self.hierarchy;
          };
          // 实时更新polygon.hierarchy
          this.options.polygon.hierarchy = new Cesium.CallbackProperty(
            _update,
            false
          );
          viewer.entities.add(this.options);
        };

        return _;
      })();
    },
    cleanEntityCollection(viewer, key) {
      var tmp = viewer.dataSources.getByName(key);
      if (tmp.length > 0) {
        tmp.map((res) => {
          viewer.dataSources.remove(res);
        });
      }
    },
    getEntityLikeName(viewer, name) {
      if (name) {
        var entities = viewer.entities.values;
        var findEntities = [];
        for (var i = 0; i < entities.length; i++) {
          var entity = entities[i];
          // console.log(entity);
          if (entity.name && entity.name.indexOf(name) !== -1) {
            findEntities.push(entity);
          }
        }
        return findEntities;
      } else {
        return [];
      }
    },
    removeEntityLikeName(viewer, name) {
      if (name) {
        var cleanEntities = this.getEntityLikeName(viewer, name);
        // 清除
        cleanEntities.map((res) => {
          viewer.entities.removeById(res.id);
        });
      } else {
        viewer.entities.removeAll();
      }
    },
    // 开始计算
    beginCalc() {
      if (polyArr.length === 0) {
        this.$message.warning("未检测到航飞区域");
        return;
      }
      var viewer = window.viewer;
      // 清除之前计算结果entity
      this.removeEntityLikeName(viewer, "uav-tmp");
      var geodesic = Cesium.BoundingRectangle.fromPoints(polyArr); // 外接矩形获取
      var rectangle = Cesium.Rectangle.fromCartesianArray(polyArr); // 外接矩形获取
      // 把面拆分成线并转换为经纬度格式存储
      var polyLines = [];
      polyArr.map((res, index) => {
        var tmp = [];
        var ellipsoid = viewer.scene.globe.ellipsoid;
        var cartesian3 = new Cesium.Cartesian3(res.x, res.y, res.z);
        var cartographic = ellipsoid.cartesianToCartographic(cartesian3);
        var cartesian31 = null;
        var cartographic1 = null;
        if (index === polyArr.length - 1) {
          // 最后一个点连接顶点
          cartesian31 = new Cesium.Cartesian3(
            polyArr[0].x,
            polyArr[0].y,
            polyArr[0].z
          );
          cartographic1 = ellipsoid.cartesianToCartographic(cartesian31);

          tmp.push([
            [
              Cesium.Math.toDegrees(cartographic.longitude),
              Cesium.Math.toDegrees(cartographic.latitude),
            ],
            [
              Cesium.Math.toDegrees(cartographic1.longitude),
              Cesium.Math.toDegrees(cartographic1.latitude),
            ],
          ]);
        } else {
          cartesian31 = new Cesium.Cartesian3(
            polyArr[index + 1].x,
            polyArr[index + 1].y,
            polyArr[index + 1].z
          );
          cartographic1 = ellipsoid.cartesianToCartographic(cartesian31);

          tmp.push([
            [
              Cesium.Math.toDegrees(cartographic.longitude),
              Cesium.Math.toDegrees(cartographic.latitude),
            ],
            [
              Cesium.Math.toDegrees(cartographic1.longitude),
              Cesium.Math.toDegrees(cartographic1.latitude),
            ],
          ]);
        }
        polyLines.push(tmp);
      });
      // 等高分割矩形
      var bool = geodesic.width < geodesic.height;
      var len = Math.floor(geodesic.height / (this.hfDistance / 2)); // 高度分割数量
      var step = rectangle.height / len; // 步长
      if (bool) {
        len = Math.floor(geodesic.width / (this.hfDistance / 2)); // 宽度分割数量
        step = rectangle.width / len; // 步长
      }
      jdArrs = []; // 交点集合
      //   console.log(rectangle, len, step)
      for (var i = 0; i < len; i++) {
        var tmp = null;
        if (bool) {
          tmp = new Cesium.Rectangle(
            rectangle.east - step * (i + 1),
            rectangle.south,
            rectangle.east - step * i,
            rectangle.north
          );
        } else {
          tmp = new Cesium.Rectangle(
            rectangle.west,
            rectangle.north - step * (i + 1),
            rectangle.east,
            rectangle.north - step * i
          );
        }
        // 弧度转换为经纬度
        var tmpLonLat = this.rectangle2LonLat(tmp);
        // 计算交点
        var tmpJdarr = [];
        polyLines.map((res) => {
          var mb = null;
          if (bool) {
            mb = turf.lineString([
              [tmpLonLat[1][0], tmpLonLat[1][1]],
              [tmpLonLat[3][0], tmpLonLat[3][1]],
            ]);
          } else {
            mb = turf.lineString([
              [tmpLonLat[1][0], tmpLonLat[1][1]],
              [tmpLonLat[0][0], tmpLonLat[0][1]],
            ]);
          }

          var intersects = turf.lineIntersect(turf.lineString(res[0]), mb);
          if (intersects.features.length > 0) {
            var tmplatlon = intersects.features[0].geometry.coordinates;
            tmpJdarr.push(tmplatlon);
          }
        });
        // 就近往返
        if (i > 0) {
          var distance1 = turf.distance(
            turf.point(tmpJdarr[0]),
            turf.point(jdArrs[jdArrs.length - 1]),
            { units: "kilometers" }
          );
          var distance2 = turf.distance(
            turf.point(tmpJdarr[1]),
            turf.point(jdArrs[jdArrs.length - 1]),
            { units: "kilometers" }
          );
          //   console.log(i, distance1, distance2)
          if (distance1 > distance2) {
            tmpJdarr = tmpJdarr.reverse();
          }
        }
        // 存储交点
        tmpJdarr.map((res) => {
          jdArrs.push(res);
        });
      }
      if (jdArrs[0][0] === jdArrs[1][0] && jdArrs[0][1] === jdArrs[1][1]) {
        jdArrs.shift();
      }

      // 线数据
      var linesArrs = [];
      // 标字
      jdArrs.map((res, index) => {
        viewer.entities.add({
          name: "uav-tmp-point",
          position: Cesium.Cartesian3.fromDegrees(res[0], res[1]),
          label: {
            text: index + "",
            font: "14pt SongTi",
            eyeOffset: new Cesium.Cartesian3(0, 0, -100),
          },
        });
        // 存储线数据
        linesArrs.push(res[0]);
        linesArrs.push(res[1]);
      });
      // 画方向线
      viewer.entities.add({
        name: "uav-tmp-line",
        // corridor polyline
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray(linesArrs),
          material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.RED),
          followSurface: true,
          width: 10,
        },
      });
    },
    // 弧度转换为经纬度
    rectangle2LonLat(coor) {
      const northwest = Cesium.Rectangle.northwest(coor);
      const southwest = Cesium.Rectangle.southwest(coor);
      const northeast = Cesium.Rectangle.northeast(coor);
      const southeast = Cesium.Rectangle.southeast(coor);

      const leftTop = [
        Cesium.Math.toDegrees(northwest.longitude),
        Cesium.Math.toDegrees(northwest.latitude),
      ];
      const leftBottom = [
        Cesium.Math.toDegrees(southwest.longitude),
        Cesium.Math.toDegrees(southwest.latitude),
      ];

      const rightTop = [
        Cesium.Math.toDegrees(northeast.longitude),
        Cesium.Math.toDegrees(northeast.latitude),
      ];

      const rightBottom = [
        Cesium.Math.toDegrees(southeast.longitude),
        Cesium.Math.toDegrees(southeast.latitude),
      ];

      return [leftTop, rightTop, leftBottom, rightBottom];
    },
    // 清理entity
    cleanEntity() {
      var viewer = window.viewer;
      this.removeEntityLikeName(viewer, "uav-");
      this.cleanEntityCollection(viewer, "uva");
      polyArr = [];
      viewer.clockViewModel.shouldAnimate = false;
      viewer.trackedEntity = undefined;
      this.isFly = false;
    },
    // 更改航飞间距触发事件
    distanceHandleChange() {
      this.beginCalc();
      // 重置飞行
      if (this.isFly) {
        this.moniFly();
      }
    },
    // 模拟飞行
    moniFly() {
      var viewer = window.viewer;
      viewer.clockViewModel.shouldAnimate = true;
      var that = this;
      that.isFly = true;
      if (polyArr.length === 0) {
        this.$message.warning("未检测到航飞区域");
        return;
      }
      // 清除上一个动画
      this.cleanEntityCollection(viewer, "uva");
      this.removeEntityLikeName(viewer, "uav-tmp-fly");
      viewer.trackedEntity = undefined;
      // 加载新动画
      const czml = [
        {
          id: "document",
          name: "uva",
          version: "1.0",
          clock: {
            interval: "2022-08-04T10:00:00Z/2022-08-04T15:00:00Z",
            currentTime: "2022-08-04T10:00:00Z",
            range: "LOOP_STOP",
            multiplier: 10,
          },
        },
        {
          id: "path",
          name: "uva-tmp-fly",
          description: "<p> 飞行器</p>",
          availability: "2022-08-04T10:00:00Z/2022-08-04T15:00:00Z",
          path: {
            material: {
              polylineOutline: {
                color: {
                  rgba: [255, 215, 0, 255],
                },
                outlineColor: {
                  rgba: [192, 192, 192, 255],
                },
                outlineWidth: 5,
              },
            },
            width: 8,
            leadTime: 10,
            // trailTime: 1000,
            resolution: 5,
          },
          billboard: {
            image:
              "",
            scale: 1.5,
            eyeOffset: {
              cartesian: [0.0, 0.0, -10.0],
            },
          },
          position: {
            epoch: "2022-08-04T10:00:00Z",
            cartographicDegrees: [],
          },
        },
      ];
      var tmp = [];
      var timesArr = [];
      var timeTmp = 0;
      var height = 500; // 飞行高度
      var v = 20; // 飞行速度
      var yc = 2; // 重复飞行延迟时间 秒
      // 手动插值
      timesArr.push(0);
      tmp.push(0);
      tmp.push(jdArrs[0][0]);
      tmp.push(jdArrs[0][1]);
      tmp.push(height + Math.random() * 5 + 5);
      for (var i = 0; i < jdArrs.length; i++) {
        var times = 0;
        if (i < jdArrs.length - 1) {
          var from = turf.point(jdArrs[i]);
          var to = turf.point(jdArrs[i + 1]);
          var options = { units: "kilometers" };
          var distance = turf.distance(from, to, options);
          times = Math.round((distance * 1000) / v);
          timeTmp += times;
          timesArr.push(timeTmp);
          tmp.push(timeTmp);
          tmp.push(jdArrs[i + 1][0]);
          tmp.push(jdArrs[i + 1][1]);
          tmp.push(height + Math.random() * 5 + 5);
        }
      }
      // 动态配置CZML
      // 动画结束时间
      var tmpsss = new Date(
        new Date(czml[0].clock.currentTime).getTime() +
          (timesArr[timesArr.length - 1] + yc) * 1000
      ).toISOString();

      var str = czml[0].clock.currentTime + "/" + tmpsss;
      czml[0].clock.interval = str;
      czml[1].availability = str;
      czml[1].path.trailTime = timesArr[2];
      czml[1].position.cartographicDegrees = tmp;

      // 加载CZML
      var dataSource = viewer.dataSources.add(Cesium.CzmlDataSource.load(czml));
      // 加载同步扫描椎体
      dataSource
        .then(function (dataSource) {
          var entity = dataSource.entities.getById("path");
          entity.viewFrom = new Cesium.Cartesian3(0.0, -1000.0, 1500.0);
          viewer.trackedEntity = entity;
          var cylinderEntitys = that.addFrustum({
            length: 510.0,
            topRadius: 0.0,
            bottomRadius: that.hfDistance / 2,
            color: Cesium.Color.GREEN.withAlpha(0.5),
          });
          var property = new Cesium.SampledPositionProperty();
          for (var ind = 0; ind < timesArr.length; ind++) {
            var time = Cesium.JulianDate.addSeconds(
              viewer.clock.currentTime,
              timesArr[ind],
              new Cesium.JulianDate()
            );
            var position = entity.position.getValue(time);
            if (position) {
              var cartographic =
                Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
              var lat = Cesium.Math.toDegrees(cartographic.latitude);
              var lng = Cesium.Math.toDegrees(cartographic.longitude);
              var hei = cartographic.height / 1.9;
              property.addSample(
                time,
                Cesium.Cartesian3.fromDegrees(lng, lat, hei)
              );
            }
          }
          cylinderEntitys.position = property;
        })
        .catch(function (error) {
          window.alert(error);
        });
    },
    // 创建视锥体
    addFrustum(option) {
      var viewer = window.viewer;
      return viewer.entities.add({
        name: "uav-tmp-fly-wxsimple",
        position: Cesium.Cartesian3.fromDegrees(114.0, 36.0, 200000.0),
        cylinder: {
          slices: option.slices,
          length: option.length,
          topRadius: option.topRadius,
          bottomRadius: option.bottomRadius,
          material: option.color,
        },
      });
    },
  },
};
</script>

<style scoped>
.show {
  display: block;
}
.uvaRoutePlanBox {
  width: 100vw;
  height: 100vh;
}
#toolTip {
  display: none;
  pointer-events: none;
  position: fixed;
  background: rgba(0, 0, 0, 0.5);
  z-index: 1000;
  opacity: 0.8;
  border-radius: 4px;
  padding: 4px 8px;
  white-space: nowrap;
  font-family: 黑体;
  color: white;
  font-weight: bolder;
  font-size: 14px;
}
/* 可视域 */
#cesiumContainer {
  width: 100%;
  height: 100%;
}
.body {
  position: fixed;
  right: calc(100% - 300px);
  top: 166px;
  z-index: 999;
  width: 300px;
  text-align: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 15px;
  color: #fff;
}
.form-item {
  margin: 5px;
}
.form-label {
  display: inline-block;
  width: 100px;
  text-align: center;
  font-size: 16px;
  font-weight: bold;
}
.form-connect {
  display: inline-block;
  /* width: calc(100% - 120px); */
}
.hide {
  display: none;
}
</style>
